package com.runchinaup.sifitbledome.ble.conn;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

/**
 * Created by nopointer on 2017/11/18.
 */

public abstract class AbsConn {

    private BluetoothAdapter daAdapter = BluetoothAdapter.getDefaultAdapter();
    private String mac;
    private Context context;
    private BluetoothGatt bluetoothGatt;
    private boolean connFlag = false;

//    private T t;

//    public AbsConn(T t) {
//        this.t = t;
//    }

    public void _conn_(String mac, Context context) {
        this.mac = mac;
        this.context = context;
        bluetoothGatt = daAdapter.getRemoteDevice(mac)
                .connectGatt(context, false, gattCallback);
    }

    public void _dis_conn() {
        if (bluetoothGatt != null) {
            bluetoothGatt.disconnect();
        }
    }

    public void _enable_notify_(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, NotificationType type) {
        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
        if (descriptor == null) return;
        switch (type) {
            case DISABLE:
                gatt.setCharacteristicNotification(characteristic, false);
                descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
                break;
            case NOTIFICATION:
                boolean success = gatt.setCharacteristicNotification(characteristic, true);
                boolean success2 = descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                break;
            case INDICATION:
                gatt.setCharacteristicNotification(characteristic, true);
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                break;
        }
        gatt.writeDescriptor(descriptor);
    }


    public abstract void onConnectResult(ConnResult connResult);

    public abstract void onLoadCharacteristic(BluetoothGatt gatt);

    public abstract void onChanged(BluetoothGattCharacteristic characteristic);

    public void onRead(BluetoothGattCharacteristic characteristic) {

    }

    public void onWrite(BluetoothGattCharacteristic characteristic) {

    }

    public void onReadRssi(int rssi) {
    }//


    final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            Log.e("debug_ble_state", "status:" + status + "---->newState:" + newState);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                if (newState == BluetoothGatt.STATE_CONNECTED) {
                    connFlag = true;
                    onConnectResult(ConnResult.CONN_SUCCESS);
                    new Timer().schedule(new TimerTask() {
                        @Override
                        public void run() {
                            gatt.discoverServices();
                        }
                    }, 200);
                } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
                    if (connFlag) {
                        onConnectResult(ConnResult.CONN_DIS);
                        close(gatt);
                    } else {// 连接超时
                        onConnectResult(ConnResult.CONN_FAILURE);
                    }
                }
            } else {
                if (connFlag) {
                    close(gatt);
                    onConnectResult(ConnResult.CONN_DIS);
                } else {
                    onConnectResult(ConnResult.CONN_FAILURE);
                }
            }

        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            onLoadCharacteristic(gatt);
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            onRead(characteristic);
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            onWrite(characteristic);
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            onChanged(characteristic);
        }
    };


    private void close(BluetoothGatt gatt) {
        if (gatt != null) {
            gatt.close();
            refreshCache(context, gatt);
        }
    }

    private static void refreshCache(Context context, BluetoothGatt gatt) {
        final BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        final List<BluetoothDevice> devices = manager.getConnectedDevices(BluetoothProfile.GATT);
        Log.e("debug_gat_conn_device", devices.size() + "");
        for (BluetoothDevice b : devices) {
            Log.e("debug_gat_conn_device", b.getAddress());
        }
        try {
            BluetoothGatt localBluetoothGatt = gatt;
            Method localMethod = localBluetoothGatt.getClass().getMethod("refresh", new Class[0]);
            if (localMethod != null) {
                localMethod.invoke(gatt, new Object[0]);
                Log.e("debug_gatt_refresh", "刷新缓存");
            }
        } catch (Exception localException) {
            Log.e("log", "An exception occured while refreshing device");
        }
    }
}
